# -*- coding: utf-8 -*-
# Author   : ZhangQing
# Time     : 2025-08-12 10:15
# File     : pool_monitor.py
# Project  : codebuddy_craft
# Desc     : 数据库连接池监控

"""
数据库连接池监控 🔍

监控数据库连接池状态，检测连接泄漏，提供连接池统计信息
"""

import asyncio
import logging
import time
from typing import Dict, Any, Optional
from datetime import datetime, timedelta

from sqlalchemy.ext.asyncio import AsyncEngine
from sqlalchemy import text

from backend.core.settings import get_settings
from backend.utils.logger import get_performance_logger

# 获取配置
settings = get_settings()
logger = logging.getLogger(__name__)
perf_logger = get_performance_logger("db_pool")

# 全局变量
_monitor_task: Optional[asyncio.Task] = None
_pool_stats: Dict[str, Any] = {
    "last_check": None,
    "total_connections": 0,
    "active_connections": 0,
    "idle_connections": 0,
    "connection_timeouts": 0,
    "peak_connections": 0,
    "connection_wait_time": 0.0,
    "history": []
}


async def start_pool_monitor(engine: AsyncEngine, interval: int = 60) -> None:
    """启动连接池监控 🚀

    Args:
        engine: 数据库引擎
        interval: 监控间隔（秒）
    """
    global _monitor_task

    if _monitor_task is not None:
        logger.warning("连接池监控已在运行")
        return

    async def monitor_loop():
        """监控循环"""
        logger.info(f"🔍 启动数据库连接池监控，间隔: {interval}秒")
        
        while True:
            try:
                await check_pool_status(engine)
                await asyncio.sleep(interval)
            except asyncio.CancelledError:
                logger.info("🛑 连接池监控已停止")
                break
            except Exception as e:
                logger.error(f"连接池监控错误: {e}")
                await asyncio.sleep(interval)

    _monitor_task = asyncio.create_task(monitor_loop())


async def stop_pool_monitor() -> None:
    """停止连接池监控 🛑"""
    global _monitor_task

    if _monitor_task is not None:
        _monitor_task.cancel()
        try:
            await _monitor_task
        except asyncio.CancelledError:
            pass
        _monitor_task = None
        logger.info("🛑 连接池监控已停止")


async def check_pool_status(engine: AsyncEngine) -> Dict[str, Any]:
    """检查连接池状态 🔍

    Args:
        engine: 数据库引擎

    Returns:
        连接池状态信息
    """
    global _pool_stats

    try:
        pool = engine.pool
        
        # 获取连接池统计信息
        total = pool.size if hasattr(pool, 'size') else 0
        checkedout = pool.checkedout if hasattr(pool, 'checkedout') else 0
        idle = total - checkedout
        
        # 更新统计信息
        _pool_stats["last_check"] = datetime.now().isoformat()
        _pool_stats["total_connections"] = total
        _pool_stats["active_connections"] = checkedout
        _pool_stats["idle_connections"] = idle
        
        # 更新峰值
        if checkedout > _pool_stats["peak_connections"]:
            _pool_stats["peak_connections"] = checkedout
        
        # 保存历史记录（最多保留24小时，每小时一个点）
        _pool_stats["history"].append({
            "timestamp": _pool_stats["last_check"],
            "total": total,
            "active": checkedout,
            "idle": idle
        })
        
        # 只保留最近24个点
        if len(_pool_stats["history"]) > 24:
            _pool_stats["history"] = _pool_stats["history"][-24:]
        
        # 记录性能指标
        perf_logger.record_metric("db_pool_total", total, "connections")
        perf_logger.record_metric("db_pool_active", checkedout, "connections")
        perf_logger.record_metric("db_pool_idle", idle, "connections")
        perf_logger.record_metric("db_pool_utilization", 
                                 round(checkedout / total * 100, 2) if total > 0 else 0, 
                                 "%")
        
        # 检测潜在的连接泄漏
        if checkedout > total * 0.9 and total >= settings.DATABASE_POOL_SIZE:
            logger.warning(f"⚠️ 潜在的连接泄漏: {checkedout}/{total} 连接已被检出")
            _pool_stats["connection_timeouts"] += 1
        
        # 每10次检查输出一次日志
        if _pool_stats.get("check_count", 0) % 10 == 0:
            logger.info(f"📊 连接池状态: {checkedout}/{total} 活跃连接, {idle} 空闲连接")
        
        _pool_stats["check_count"] = _pool_stats.get("check_count", 0) + 1
        
        return _pool_stats
    
    except Exception as e:
        logger.error(f"检查连接池状态失败: {e}")
        return {"error": str(e)}


async def test_connection_performance(engine: AsyncEngine, iterations: int = 10) -> Dict[str, Any]:
    """测试连接性能 ⏱️

    Args:
        engine: 数据库引擎
        iterations: 测试迭代次数

    Returns:
        连接性能测试结果
    """
    results = {
        "avg_connection_time_ms": 0,
        "min_connection_time_ms": float('inf'),
        "max_connection_time_ms": 0,
        "success_rate": 0,
        "iterations": iterations
    }
    
    success_count = 0
    total_time = 0
    
    for i in range(iterations):
        try:
            start_time = time.time()
            
            async with engine.connect() as conn:
                await conn.execute(text("SELECT 1"))
            
            end_time = time.time()
            elapsed_ms = (end_time - start_time) * 1000
            
            # 更新统计
            total_time += elapsed_ms
            success_count += 1
            
            results["min_connection_time_ms"] = min(results["min_connection_time_ms"], elapsed_ms)
            results["max_connection_time_ms"] = max(results["max_connection_time_ms"], elapsed_ms)
            
            # 短暂暂停，避免压力过大
            await asyncio.sleep(0.1)
            
        except Exception as e:
            logger.error(f"连接测试失败: {e}")
    
    # 计算最终结果
    if success_count > 0:
        results["avg_connection_time_ms"] = round(total_time / success_count, 2)
        results["min_connection_time_ms"] = round(results["min_connection_time_ms"], 2)
        results["max_connection_time_ms"] = round(results["max_connection_time_ms"], 2)
    else:
        results["min_connection_time_ms"] = 0
    
    results["success_rate"] = round(success_count / iterations * 100, 2)
    
    # 记录性能指标
    perf_logger.record_metric("db_connection_time_avg", results["avg_connection_time_ms"], "ms")
    perf_logger.record_metric("db_connection_success_rate", results["success_rate"], "%")
    
    return results


def get_pool_stats() -> Dict[str, Any]:
    """获取连接池统计信息 📊

    Returns:
        连接池统计信息
    """
    return _pool_stats


async def reset_pool_stats() -> None:
    """重置连接池统计信息 🔄"""
    global _pool_stats
    
    _pool_stats = {
        "last_check": None,
        "total_connections": 0,
        "active_connections": 0,
        "idle_connections": 0,
        "connection_timeouts": 0,
        "peak_connections": 0,
        "connection_wait_time": 0.0,
        "history": [],
        "check_count": 0
    }
    
    logger.info("🔄 连接池统计信息已重置")


# 导出所有公共函数
__all__ = [
    'start_pool_monitor',
    'stop_pool_monitor',
    'check_pool_status',
    'test_connection_performance',
    'get_pool_stats',
    'reset_pool_stats',
]